<?php

/*
 * core/service_caller.php
 *
 * Call service's methods.
 * Based on a path to designate which service to call and which method.
 * 
 * Service are callable through a path like: /site/subDirectory/ServiceName/MethodName
 */

require_once( 'auth.php' );

/*
 * ServiceCaller Object
 */
class ServiceCaller
{
	// service path + filename
	private $svcFilename = null;

	// service object name
	private $svcName = null;

	// service method name
	private $svcMethod = null;

	// service instance handler
	private $svcInstance = null;

	/*
	 * constructor
	 */
	public function __construct()
	{
	}

	/*
	 * parse()
	 * parse given path and arguments to determine which service to load/call
	 */
	public function parse( $path )
	{
		// path: /core/Auth/logout
		// args: array( blah, toto, array(0,1,2) )
	
		if( preg_match_all( '|^/(.*)/(.*)/(.*)$|', $path, $matches ) === FALSE )
		{
			$e = 'ServiceCaller::parse: unable to parse path';
			$e .= ( Conf::$c['debug']['active'] ) ? ' ('.Util::getPregLastErrorString().')' : '';
			setError( $e );
			return false;
		}

		// check if good
		list( list($unused), list($p), list($svc), list($mth) ) = $matches;
		if( ($p == '') || ($svc == '') || ($mth == '') )
		{
			setError( 'ServiceCaller::parse: path does not match expected arguments' );
			return false;
		}

		$this->svcFilename = $p . '/' . strtolower( $svc ) . '_service.php';
		$this->svcName = $svc . 'Service';
		$this->svcMethod = $mth;

		if( !$this->load() )
		{
			setError( 'ServiceCaller::parse: unable to load service.' );
			return false;
		}

		return true;
	}

	/*
	 * load()
	 * load service and instanciate it
	 * return boolean
	 */
	private function load()
	{
		if( !file_exists($this->svcFilename) )
		{
			$e = 'ServiceCaller::load: service does not exist';
			$e .= (Conf::$c['debug']['active']) ? ' (filename not exist: '.$this->svcFilename.')' : '';
			setError( $e );
			return false;
		}

		include( $this->svcFilename );

		$this->svcInstance = new $this->svcName();
		return true;
	}

	/*
	 * call()
	 * check permission and call service->method( args )
	 * return call result
	 */
	public function call( $args )
	{
		// check permissions && call method && return result && handle generated latency

		if( Conf::$c['rpc']['debug']['right_check'] )
		{
			// check if method is registered and public
			if( !$this->svcInstance->isPublicMethod( $this->svcMethod ) )
			{
				// check rigths
				if( !Auth::isCallAllowed( $this->svcName, $this->svcMethod ) )
				{
					$txt = 'Call not allowed';
					$txt .= Conf::$c['debug']['active'] ? ' ('.$this->svcName.'::'.$this->svcMethod.')' : '';
					error( $txt );
					return null;
				}
			}
		}

		// check arguments
		if( !$this->svcInstance->checkArguments( $this->svcMethod, $args ) )
		{
			error();
			return null;
		}

		// call service->method
		$result = call_user_func_array( array($this->svcInstance,$this->svcMethod), $args );

		if( is_array($result) || is_object($result) || is_null($result) )
		{
			// no change to array
		}
		elseif( is_bool($result) || is_int($result) || 
						is_string($result) || is_float($result) || 
						is_double($result) )
		{
			$result = array( 'o'=>$result );
		}
		else
		{
			error( 'rpc.php: unknown result type for "'.print_r($result).'"' );
		}

		// generated latency
		if( Conf::$c['rpc']['debug']['generated_latency'] > 0 )
			sleep( Conf::$c['rpc']['debug']['generated_latency'] );

		return $result;
	}
};



?>
